package priv.conceit.study.book.thread.chapter3.parts7;

import java.util.concurrent.TimeUnit;

/**
 * 3.7
 * Interrupt方法
 * <p>
 * {@link Thread#interrupt()}
 * 标记线程状态 打断阻塞状态
 * <p>
 * {@link Thread#isInterrupted()}
 * 测试该线程是否被中断 线程的中断状态 不受该方法的影响
 * 成员方法
 * <p>
 * {@link Thread#interrupted()}
 * 测试线程是否被中断
 * 静态方法
 * 调用该方法会直接擦除掉标识
 * 如果该线程已经被打断了 那么第一次调用本方法会返回true 并立即擦除标识
 * 之后的调用都会返回false
 * 除非线程在此期间又一次被打断
 * <p>
 * <p>
 * 以下方法会使线程进入阻塞状态
 * {@link Object#wait()}
 * {@link Object#wait(long, int)}
 * {@link Object#wait(long)}
 * <p>
 * <p>
 * {@link Thread#sleep(long)}
 * {@link Thread#sleep(long, int)}
 * <p>
 * {@link Thread#join()}
 * {@link Thread#join(long)}
 * {@link Thread#join(long, int)}
 * 以及其他方法
 * <p>
 * 使用以上方法 会使线程进入阻塞状态
 * 而使用另一个线程的interrupt方法会打断阻塞(添加标记并抛出异常)
 * 一旦线程在阻塞的情况下被打断，一般都会抛出一个{@link InterruptedException}异常
 * 这个异常 就像一个信号(signal)一样通知当前线程被打断了
 * 在线程内部存在interrupt flag的标识，如果线程被另一个线程interrupt 标记启用
 * -如果一个线程已经终结 那么会忽略此命令
 * -interrupt()不能中断在运行中的线程，它只能改变中断状态而已。
 * <p>
 * <p>
 * 核心-->
 * 如果线程处在阻塞状态 线程被另一个线程interrupt 标记启用 抛出异常
 * 并且在抛出异常后立即将线程的中断标示位清除，即重新设置为false
 * 为什么要复位-->可中断方法捕获到中断型号后，为了不影响线程其他方法的执行，将标识复位。
 * <p>
 * 如果是其他状态 则标记为true 并向上抛出异常,线程状态没有受到影响
 *
 * @author conceit
 * @since 1.0.0, 2019/6/18
 */
public class Interrupt {

	public static void main(String[] args) {
		//testInterruptedException();
		//testIsInterrupted();
		//testInterrupted();
	}

	/**
	 * 线程1试图休眠1分钟
	 * 第一种情况是 还在runnable情况下被打断了线程
	 * <p>
	 * 第二种是主线程等待1秒钟 让线程1阻塞 结果main线程在1秒钟之后打断了线程1的阻塞状态
	 */
	public static void testInterruptedException() {
		Thread thread1 = new Thread(() -> {
			try {
				TimeUnit.MINUTES.sleep(1L);
			} catch (InterruptedException e) {
				System.out.println("thread1 出现了 InterruptedException");
				e.printStackTrace();
			}
		});
		thread1.setName("thread1");
		thread1.start();


//		//如果RUNNABLE下打断
		System.out.println("thread1 state-->" + thread1.getState());//RUNNABLE
		// false
		System.out.println("thread1.isInterrupted()-->" + thread1.isInterrupted());
		thread1.interrupt();
		// true
		System.out.println("thread1.isInterrupted()-->" + thread1.isInterrupted());
		System.out.println("86 thread1 state-->" + thread1.getState());

		//阻塞情况下打断 时间要足够长 不然线程的状态不会受到影响
//		try {
//			TimeUnit.SECONDS.sleep(1L);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		System.out.println("thread1 state-->"+thread1.getState());//TIMED_WAITING
//		//false
//		System.out.println("thread1.isInterrupted()-->"+thread1.isInterrupted());
//		thread1.interrupt();
//		//false
//		System.out.println("thread1.isInterrupted()-->"+thread1.isInterrupted());
//		System.out.println("97 thread1 state-->"+thread1.getState());
	}


	/**
	 * {@link Thread#isInterrupted()}
	 * 对线程不进行阻断处理
	 * 并将线程设置为守护线程，主线程的结束，导致jvm中没有非守护线程为结束
	 */
	public static void testIsInterrupted() {
		Thread thread1 = new Thread(() -> {
			while (true) {
				//
			}
		});
		thread1.setName("thread1");
		thread1.setDaemon(true);
		thread1.start();

		System.out.println("thread1 state-->" + thread1.getState());
		System.out.println("thread1 isInterrupted-->" + thread1.isInterrupted());
		thread1.interrupt();
		System.out.println("thread1 state-->" + thread1.getState());
		System.out.println("thread1 isInterrupted-->" + thread1.isInterrupted());
	}

	/**
	 * {@link Thread#interrupted()}
	 * 线程没有被中断 标识为false
	 * 首次使用{@link Thread#interrupted()}方法，返回true 并立即擦除标识
	 * 之后的调用都会返回false
	 * 除非线程在此期间又一次被打断
	 */
	public static void testInterrupted() {
		Thread thread1 = new Thread() {
			@Override
			public void run() {
				while (true) {
					System.out.println(Thread.interrupted());
				}

			}
		};
		thread1.setName("thread1");
		thread1.setDaemon(true);
		thread1.start();
		System.out.println(thread1.getState());
		try {
			TimeUnit.MILLISECONDS.sleep(5L);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println(thread1.getState());
	}


}
